package utils.lang;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.Temporal;

public class DateUtil {


    private static final String STANDARD_DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
    private static final String SHORT_DATETIME_PATTERN    = "yyyyMMddHHmmss";
    private static final String LITTLE_DATETIME_PATTERN   = "yyMMddHHmmss";
    private static final String STANDARD_DATE_PATTERN     = "yyyy-MM-dd";
    private static final String SHORT_DATE_PATTERN        = "yyyyMMdd";
    private static final String LITTLE_DATE_PATTERN       = "yyMMdd";
    private static final String STANDARD_TIME_PATTERN     = "HH:mm:ss";
    private static final String SHORT_TIME_PATTERN        = "HHmmss";


    private static final DateTimeFormatter STANDARD_DATETIME_FORMATTER = DateTimeFormatter.ofPattern(STANDARD_DATETIME_PATTERN);
    private static final DateTimeFormatter SHORT_DATETIME_FORMATTER    = DateTimeFormatter.ofPattern(SHORT_DATETIME_PATTERN);
    private static final DateTimeFormatter LITTLE_DATETIME_FORMATTER   = DateTimeFormatter.ofPattern(LITTLE_DATETIME_PATTERN);
    private static final DateTimeFormatter STANDARD_DATE_FORMATTER     = DateTimeFormatter.ofPattern(STANDARD_DATE_PATTERN);
    private static final DateTimeFormatter SHORT_DATE_FORMATTER        = DateTimeFormatter.ofPattern(SHORT_DATE_PATTERN);
    private static final DateTimeFormatter LITTLE_DATE_FORMATTER       = DateTimeFormatter.ofPattern(LITTLE_DATE_PATTERN);
    private static final DateTimeFormatter STANDARD_TIME_FORMATTER     = DateTimeFormatter.ofPattern(STANDARD_TIME_PATTERN);
    private static final DateTimeFormatter SHORT_TIME_FORMATTER        = DateTimeFormatter.ofPattern(SHORT_TIME_PATTERN);
    private static final DateTimeFormatter MONTH_FORMATTER             = DateTimeFormatter.ofPattern("yyyyMM");


    /**
     * 返回当前的日期
     *
     * @return yyyy-MM-dd
     */
    public static LocalDate currLocalDate() {
        return LocalDate.now();
    }

    /**
     * 返回当前时间
     *
     * @return HH:mm:ss
     */
    public static LocalTime currLocalTime() {
        return LocalTime.now();
    }

    /**
     * 返回当前日期时间
     *
     * @return yyyy-MM-dd HH:mm:ss
     */
    public static LocalDateTime currLocalDateTime() {
        return LocalDateTime.now();
    }

    /**
     * 获取当前日期
     *
     * @return yyyy-MM-dd
     */
    public static String currDate() {
        return currLocalDate().toString();
    }

    /**
     * 返回当前日期
     *
     * @return yyyyMMdd
     */
    public static String currShortDate() {
        return currLocalDate().format(SHORT_DATE_FORMATTER);
    }

    /**
     * 返回当前日期
     *
     * @return yyMMdd
     */
    public static String currShortDateStr() {
        return currLocalDate().format(LITTLE_DATE_FORMATTER);
    }


    /**
     * 获取当前时间
     *
     * @return yyyy-MM-dd HH:mm:ss
     */
    public static String currDateTime() {
        return currLocalDateTime().format(STANDARD_DATETIME_FORMATTER);
    }

    /**
     * 判断当前日期是否在当前日期之前
     *
     * @param date 比较日期 yyyy-MM-dd
     * @return <p>比较日期 > 当前日期 true</p>
     */

    public static boolean isBeforeDateTimeNow(String date) {
        LocalDateTime now = parseLocalDateTime(date, STANDARD_DATETIME_PATTERN);
        return currLocalDateTime().isAfter(now);
    }

    /**
     * 判断当前日期是否在当前日期之后
     *
     * @param date 比较日期 yyyy-MM-dd HH:mm:ss
     * @return <p>比较日期 > 当前日期 true</p>
     */
    public static boolean isAfterDateTimeNow(String date) {
        LocalDateTime now = parseLocalDateTime(date, STANDARD_DATETIME_PATTERN);
        return currLocalDateTime().isBefore(now);
    }

    /**
     * 判断当前日期是否在当前日期之前
     *
     * @param date 比较日期 yyyy-MM-dd
     * @return <p>比较日期 > 当前日期 true</p>
     */
    public static boolean isBeforeDateNow(String date) {
        LocalDate now = parseLocalDate(date, STANDARD_DATE_PATTERN);
        return currLocalDate().isAfter(now);
    }

    /**
     * 判断当前日期是否在当前日期之后
     *
     * @param date 比较日期 yyyy-MM-dd HH:mm:ss
     * @return <p>比较日期 > 当前日期 true</p>
     */
    public static boolean isAfterDateNow(String date) {
        LocalDate now = parseLocalDate(date, STANDARD_DATE_PATTERN);
        return currLocalDate().isBefore(now);
    }

    /**
     * 判断当前时间是否在比较时间之前
     *
     * @param time 比较时间
     * @return ture/false
     */
    public static boolean isBeforeTimeNow(String time) {
        return currLocalTime().isAfter(parseLocalTime(time, STANDARD_TIME_PATTERN));
    }

    /**
     * 判断当前时间是否在比较时间之后
     *
     * @param time 比较时间
     * @return
     */
    public static boolean isAfterTimeNow(String time) {
        return currLocalTime().isBefore(parseLocalTime(time, STANDARD_TIME_PATTERN));
    }

    /**
     * 判断是否在两个日期范围内
     *
     * @param start 开始日期 yyyy-MM-dd
     * @param end   结束日期 yyyy-MM-dd
     * @return true/false
     */
    public static boolean isBetweenDate(String start, String end) {
        return isAfterDateTimeNow(getMaxDateTimeStr(end)) && isBeforeDateTimeNow(getMinDateTimeStr(start));
    }

    /**
     * 获取今天最小的时间
     *
     * @return yyyy-MM-dd HH:mm:ss
     */
    public static String getMinDateTimeStr(String date) {
        return formatLocalDateTime(LocalDate.parse(date, STANDARD_DATE_FORMATTER).atTime(LocalTime.MIN), STANDARD_DATETIME_PATTERN);
    }

    /**
     * 获取今天最大的时间
     *
     * @return yyyy-MM-dd HH:mm:ss
     */
    public static String getMaxDateTimeStr(String date) {
        return formatLocalDateTime(LocalDate.parse(date, STANDARD_DATE_FORMATTER).atTime(LocalTime.MAX), STANDARD_DATETIME_PATTERN);
    }

    /**
     * 获取今天最小的时间
     *
     * @return yyyy-MM-dd HH:mm:ss
     */
    public static LocalDateTime getMinDateTime(String date) {
        return LocalDate.parse(date, STANDARD_DATE_FORMATTER).atTime(LocalTime.MIN);
    }

    /**
     * 获取今天最大的时间
     *
     * @return yyyy-MM-dd HH:mm:ss
     */
    public static LocalDateTime getMaxDateTime(String date) {
        return LocalDate.parse(date, STANDARD_DATE_FORMATTER).atTime(LocalTime.MAX);
    }

    /**
     * 获取今天最大的时间
     *
     * @return yyyy-MM-dd HH:mm:ss
     */
    public static LocalDateTime getMaxDateTime(LocalDate date) {
        return date.atTime(LocalTime.MAX);
    }

    /**
     * 获取当前年月份
     *
     * @return yyyyMM
     */
    public static String currYearMonth() {
        return currLocalDate().format(MONTH_FORMATTER);
    }

    /**
     * 获取当前年月日时分秒
     *
     * @return yyyyMMddHHmmss
     */
    public static String currShortDateTime() {
        return currLocalDateTime().format(SHORT_DATETIME_FORMATTER);
    }

    /**
     * 获取当前年月日时分秒
     *
     * @return yyMMddHHmmss
     */
    public static String currShortDateTimeStr() {
        return currLocalDateTime().format(LITTLE_DATETIME_FORMATTER);
    }

    /**
     * 获取当前时间
     *
     * @return HHmmss
     */
    public static String currShortTime() {
        return currLocalTime().format(SHORT_TIME_FORMATTER);
    }

    /**
     * 字符串转换为日期
     *
     * @param dateStr 日期参数
     * @param pattern 格式化模式
     * @return <code>pattern</code>
     */
    public static LocalDate parseLocalDate(String dateStr, String pattern) {
        return LocalDate.parse(dateStr, DateTimeFormatter.ofPattern(pattern));
    }

    /**
     * 字符串转换日期时间
     *
     * @param dateTimeStr 日期时间参数
     * @param pattern     格式化模式
     * @return <code>pattern</code>
     */
    public static LocalDateTime parseLocalDateTime(String dateTimeStr, String pattern) {
        return LocalDateTime.parse(dateTimeStr, DateTimeFormatter.ofPattern(pattern));
    }

    /**
     * 字符串转换时间
     *
     * @param timeStr 时间参数
     * @param pattern 格式化参数
     * @return <code>pattern</code>
     */
    public static LocalTime parseLocalTime(String timeStr, String pattern) {
        return LocalTime.parse(timeStr, DateTimeFormatter.ofPattern(pattern));
    }

    /**
     * 日期转换字符串
     *
     * @param date    日期参数
     * @param pattern 格式化参数
     * @return <code>pattern</code>
     */
    public static String formatLocalDate(LocalDate date, String pattern) {
        return date.format(DateTimeFormatter.ofPattern(pattern));
    }

    /**
     * 日期时间转换字符串
     *
     * @param datetime 日期参数
     * @param pattern  格式化参数
     * @return <code>pattern</code>
     */
    public static String formatLocalDateTime(LocalDateTime datetime, String pattern) {
        return datetime.format(DateTimeFormatter.ofPattern(pattern));
    }

    /**
     * 时间转换字符串
     *
     * @param time    日期参数
     * @param pattern 格式化参数
     * @return <code>pattern</code>
     */
    public static String formatLocalTime(LocalTime time, String pattern) {
        return time.format(DateTimeFormatter.ofPattern(pattern));
    }


    /**
     * 日期相隔天数
     *
     * @param startDateInclusive 开始日期 yyyy-MM-dd
     * @param endDateExclusive   结束日期 yyyy-MM-dd
     * @return 天数
     */
    public static int periodDays(LocalDate startDateInclusive, LocalDate endDateExclusive) {
        return Period.between(startDateInclusive, endDateExclusive).getDays();
    }

    /**
     * 日期相隔天数
     *
     * @param startDateInclusive 开始日期 yyyy-MM-dd
     * @param endDateExclusive   结束日期 yyyy-MM-dd
     * @return 天数
     */
    public static int periodDays(String startDateInclusive, String endDateExclusive) {
        return Period.between(parseLocalDate(startDateInclusive, STANDARD_DATE_PATTERN),
                parseLocalDate(endDateExclusive, STANDARD_DATE_PATTERN)).getDays();
    }

    /**
     * 日期相隔小时
     *
     * @param startInclusive 开始日期
     * @param endExclusive   结束日期
     * @return
     */
    public static long durationHours(Temporal startInclusive, Temporal endExclusive) {
        return Duration.between(startInclusive, endExclusive).toHours();
    }

    /**
     * 日期相隔小时
     *
     * @param startInclusive 开始日期 HH:mm:ss
     * @param endExclusive   结束日期 HH:mm:ss
     * @return 小时
     */
    public static long durationHours(String startInclusive, String endExclusive) {

        return Duration.between(parseLocalTime(startInclusive, STANDARD_TIME_PATTERN),
                parseLocalTime(endExclusive, STANDARD_TIME_PATTERN)).toHours();
    }

    /**
     * 日期相隔分钟
     *
     * @param startInclusive 开始日期
     * @param endExclusive   结束日期
     * @return 分钟
     */
    public static long durationMinutes(Temporal startInclusive, Temporal endExclusive) {
        return Duration.between(startInclusive, endExclusive).toMinutes();
    }

    public static long oddMinutesOfToday() {
        return Duration.between(currLocalTime(), getMaxDateTime(currDate())).toMinutes();
    }


    public static long oddSecondsOfToday() {
        String date = formatLocalDate(plusDay(1), STANDARD_DATE_PATTERN);
        return Duration.between(currLocalTime(), getMinDateTime(date)).toMillis() / 1000;
    }

    public static long oddSecondOfDate(String date) {
        String param = formatLocalDate(plusDay(date, 1), STANDARD_DATE_PATTERN);
        return Duration.between(currLocalTime(), getMaxDateTime(param)).toMillis() / 1000;
    }

    /**
     * 调整日期
     *
     * @param days 日期
     * @return 调整后的日期
     */
    public static LocalDate plusDay(int days) {
        return LocalDate.now().plusDays(days);
    }

    /**
     * 调整日期
     *
     * @param days 日期
     * @return 调整后的日期
     */
    public static LocalDate plusDay(String date, int days) {
        return parseLocalDate(date, STANDARD_DATE_PATTERN).plusDays(days);
    }

    /**
     * 调整月
     *
     * @param months 月
     * <p>
     * For example, 2007-03-31 plus one month would result in the invalid date
     * 2007-04-30. Instead of returning an invalid result, the last valid day
     * of the month, 2007-04-30, is selected instead.
     * <p>
     * @return 调整后的日期
     */
    public static LocalDate plusMonth(int months) {
        return LocalDate.now().plusMonths(months).minusDays(1);
    }

    /**
     * 调整年
     *
     * @param years 年
     * @return 调整后的日期
     */
    public static LocalDate plusYear(int years) {
        return LocalDate.now().plusYears(years);
    }

    /**
     * 是否当天
     *
     * @param date 日期
     * @return
     */
    public static boolean isToday(LocalDate date) {
        return currLocalDate().equals(date);
    }

    public static Long toEpochMilli(LocalDateTime dateTime) {
        return dateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
    }



}
